package com.y.fund.utils;


import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DateTimeUtil {


    /**
     * 通用的时间格式化 格式
     */
    public static final String TimePatternStr = "yyyy-MM-dd HH:mm:ss";

    /**
     * 获取中国的当前周的第一天
     */
    public static LocalDate GetCurrWeekFirstDay4CN() {
        Calendar cal = Calendar.getInstance();
        try {
            cal.set(Calendar.DAY_OF_WEEK, 2);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cal.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 获取系统时间
     *
     * @return
     */
    public static Date str2Date(String dateStr) {
        if (null == dateStr) {
            return null;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateStr.length() == 16 ? "yyyy-MM-dd HH:mm" : "yyyy-MM-dd HH:mm:ss");
        LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
        return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取系统时间
     *
     * @return
     */
    public static String getDateTimeNow() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }

    /**
     * 将毫秒数转为本地时间格式
     */
    public static LocalDateTime ToLocalDateTime(final Long currentTimeMillis) {
        if (null == currentTimeMillis) {
            return null;
        }
        return Instant.ofEpochMilli(currentTimeMillis).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 将毫秒数转为本地时间格式
     */
    public static LocalDate ToLocalDate(final Long currentTimeMillis) {
        if (null == currentTimeMillis) {
            return null;
        }
        return Instant.ofEpochMilli(currentTimeMillis).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 返回传入日期的年月；格式：yyyyMM
     */
    public static Integer GetYyyyMM(final LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        return Integer.valueOf("" + localDate.getYear() + ((localDate.getMonthValue() > 9) ? "" : "0") + localDate.getMonthValue());
    }

    /**
     * 返回传入日期的年月字符串；格式：yyyy-MM
     */
    public static String GetYyyyMMStr(final LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        return "" + localDate.getYear() + "-" + ((localDate.getMonthValue() > 9) ? "" : "0") + localDate.getMonthValue();
    }
    
    /**
     * 返回传入日期的年月；格式：yyyy-MM
     */
    public static Integer GetYyyyMM(Long time) {
        if (null == time) {
            return null;
        }
        return Integer.valueOf(new SimpleDateFormat("yyyyMM").format(new Date(time)));
    }

    /**
     * 获取传入时间的字符串日期；格式：yyyy-MM-dd
     */
    public static String getYyyyMMdd(long ctime) {
        return new SimpleDateFormat("yyyy-MM-dd").format(new Date(ctime));
    }

    /**
     * 根据传入字符串【yyyy-MM-dd】日期获取本地日期时间；
     */
    public static LocalDateTime YyyyMMdd2DateTime(String dateStr) {
        if (null == dateStr) {
            return null;
        }
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return LocalDateTime.parse(dateStr, formatter);
        } catch (Exception e) {
            e = null;
        }
        return null;
    }

    /**
     * 获取传入时间的字符串日期；格式：yyyy-MM-dd
     */
    public static Date parseYyyyMMdd(String dateStr) {
        if (null == dateStr) {
            return null;
        }
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
            return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
        } catch (Exception e) {
            e = null;
        }
        return null;
    }

    /**
     * 获取传入日期的字符串日期；格式：yyyy-MM-dd
     */
    public static String getYyyyMMdd(Date date) {
        if (null == date) {
            return null;
        }
        return new SimpleDateFormat("yyyy-MM-dd").format(date);
    }

    /**
     * 获取当前日期的整数形式；yyyyMMdd
     */
    public static Integer getNowDate() {
        try {
            return Integer.valueOf(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取系统时间(自定义格式)
     *
     * @return
     */
    public static String getDateTimeNow(String formatStr) {

        return new SimpleDateFormat(formatStr).format(new Date());
    }

    /**
     * 获取系统时间(自定义格式)
     *
     * @return
     */
    public static String getDateTime(long timeMillis) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timeMillis));
    }

    /**
     * 根据 LocalDate 返回 yyyy-MM-dd 的字符串
     */
    public static String GetYyyyMMddStr(LocalDate locDate) {
        if (null == locDate) {
            return null;
        }
        int mv = locDate.getMonthValue();
        int dm = locDate.getDayOfMonth();
        return locDate.getYear() + "-" + ((mv < 10) ? "0" : "") + mv + "-" + ((dm < 10) ? "0" : "") + dm;
    }


    /**
     * 自定义转换格式
     *
     * @return
     */
    public static String getDateFormart(String dateStr, String formatStr) {

        return getDateFormart(dateStr, new SimpleDateFormat(formatStr));
    }

    /**
     * 毫秒数时间戳自定义转换格式
     *
     * @return
     */
    public static String getDateFormartForMill(Long timeMillis, String formatStr) {

        return new SimpleDateFormat(formatStr).format(new Date(timeMillis));
    }

    /**
     * 计算时间 两个时间相差距离多少天多少小时多少分
     *
     * @return
     */
    public static String getDistanceTime(String starTime, String endTime) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        long day = 0;
        long hour = 0;
        long min = 0;
        try {
            long sTime = df.parse(starTime).getTime();
            long eTime = df.parse(endTime).getTime();
            long diff = eTime - sTime;

            day = diff / (24 * 60 * 60 * 1000);
            hour = (diff / (60 * 60 * 1000) - day * 24);
            min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);

        } catch (ParseException e) {
            e.printStackTrace();
        }
        if (hour == 0) {
            return min + "分";
        } else if (day == 0) {
            return hour + "小时" + min + "分";
        } else
            return day + "天" + hour + "小时" + min + "分";

    }

    /**
     * 转yyyy-MM-dd HH:mm
     *
     * @return
     */
    public static String getyyyyMMddHHmm(String dateStr) {
        if (StrUtil.isBlankIncNullStr(dateStr)) {
            return "";
        }
        return getDateFormart(dateStr, new SimpleDateFormat("yyyy-MM-dd HH:mm"));
    }

    /**
     * 转MM-dd HH:mm
     *
     * @return
     */
    public static String getMMddHHmm(String dateStr) {
        if (StrUtil.isBlankIncNullStr(dateStr)) {
            return "";
        }
        String date = getDateFormart(dateStr, new SimpleDateFormat("yyyy-MM-dd HH:mm"));
        date = date.substring(5);
        return date;
    }

    private static String getDateFormart(String dateStr, SimpleDateFormat sdf) {

        try {
            return sdf.format(sdf.parse(dateStr));
        } catch (ParseException e) {

            System.err.println(e.getMessage());
        }

        return null;
    }

    /**
     * 将yyyy-MM-dd的时期格式转换为时间戳
     */
    public static Long dateToStamp(String s) throws ParseException {
//	    String res;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = simpleDateFormat.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        long ts = date.getTime();
//	    res = String.valueOf(ts);
        return ts;
    }

    /**
     * 取List中String的最大值
     *
     * @param dates
     * @return
     */
    public static String maxDate(List<String> dates) {
        String ret = "";
        for (int i = 0; i < dates.size(); i++) {
            if (ret.compareTo(dates.get(i)) < 0) {
                ret = dates.get(i);
            }
        }
        return ret;
    }

    /**
     * 日期加减
     *
     * @param date 字符串日期
     * @param time 加多少分钟
     * @return
     */
    public static String addDate(String date, BigDecimal time, Map<String, String> dayoffMap, List<String> workTimeList) {
        if (time == null) {
            time = new BigDecimal(180);
        }
        //获取区间结束时间
        String sectionEndTime = sectionDateEnd(date, workTimeList);
        //开始时间和区间结束时间相减，计算区间剩余可用时间
        String diString = getDistanceTime(date, sectionEndTime);
        String[] diList = diString.split("小时");
        BigDecimal diBig = new BigDecimal(0);
        //判断是否超过60分钟
        if (diList.length > 1) {
            diBig = new BigDecimal(Integer.parseInt(diList[0]) * 60 + Integer.parseInt(diList[1].replace("分", "")));
        } else {
            diBig = new BigDecimal(Integer.parseInt(diList[0].replace("分", "")));
        }
        //标准工时与区间剩余可用时间相减，如果标准工时<=区间剩余可用时间，则正常计算结束时间
        //若标准工时>区间剩余可用时间，则根据设置的正常工作时间进行比较，递归加工时
        BigDecimal comMinute = time.subtract(diBig);
        if (comMinute.compareTo(new BigDecimal(0)) <= 0) {
            int second = time.multiply(new BigDecimal(60)).setScale(0, RoundingMode.DOWN).intValue();
            String ret = "";
            Date d = new Date();
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            try {
                d = df.parse(date);
                ret = df.format(new Date(d.getTime() + second * 1000L));
            } catch (ParseException e) {

                e.printStackTrace();
            }
            return ret;
        } else {
            String morningTimeS = workTimeList.get(0);
            String morningTimeE = workTimeList.get(1);
            String afternoonS = workTimeList.get(2);
            String afternoonE = workTimeList.get(3);
            int month = Integer.parseInt(date.split("-")[1]);
            int secEndHour = Integer.parseInt(sectionEndTime.split(" ")[1].split(":")[0]);
            int afternoonStartHour = Integer.parseInt(afternoonS.split(":")[0]);
            String date2 = null;
            if (secEndHour <= afternoonStartHour) {
                String day = date.split(" ")[0];
                date2 = day + " " + afternoonS;
            } else {
                Date d = new Date();
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                try {
                    d = df.parse(date + ".000");
                } catch (ParseException e) {

                    e.printStackTrace();
                }

                String zDate = "";
                String day = "";

                zDate = df.format(new Date(d.getTime() + 24 * 60 * 60 * 1000));
                day = zDate.split(" ")[0];
                while (dayoffMap.containsKey(day)) {
                    try {
                        d = df.parse(zDate);
                    } catch (ParseException e) {

                        e.printStackTrace();
                    }
                    zDate = df.format(new Date(d.getTime() + 24 * 60 * 60 * 1000));
                    day = zDate.split(" ")[0];
                }

                date2 = day + " " + morningTimeS;
            }

            return addDate(date2, comMinute, dayoffMap, workTimeList);
        }

    }

    /**
     * 计算date的该区间结束时间
     *
     * @param date 传入计划开始时间
     * @return
     */
    public static String sectionDateEnd(String date, List<String> workTimeList) {
        String morningTimeE = workTimeList.get(1);
        String afternoonE = workTimeList.get(3);
        String timeSet = date.split(" ")[1].substring(0, 5).replace(":", "");
        String secTimeEnd = morningTimeE.substring(0, 5).replace(":", "");
        //判断开始时间是否大于上午区间结束时间
        //是：区间结束时间设定为当天下午下班时间  否：当天上午下班时间
        if (timeSet.compareTo(secTimeEnd) <= 0) {
            String day = date.split(" ")[0];
            String retTime = day + " " + morningTimeE;
            return retTime;
        } else {
            String day = date.split(" ")[0];
            String retTime = day + " " + afternoonE;
            return retTime;
        }
    }

    /**
     * 正则匹配字符串是否为时间格式
     */
    public static boolean isDate(String date) {
        Matcher mat = DATE_PATTERN.matcher(date);
        return mat.matches();
    }

    private static final DateTimeFormatter YMD_14 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static final String DATE_REGEX = "^((\\d{2}(([02468][048])|([13579][26]))[\\-/\\s]?((((0?[13578])|(1[02]))"
            + "[\\-/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-/\\s]?((0?[1-9])|([1-2][0-9])))))"
            + "|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-/\\s]?((((0?[13578])|(1[02]))[\\-/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))"
            + "[\\-/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))";

    public static final String PHONE_REGEX = "((\\d{11})|^((\\d{7,8})|(\\d{4}|\\d{3})-(\\d{7,8})|(\\d{4}|\\d{3})-(\\d{7,8})-(\\d{4}|\\d{3}|\\d{2}|\\d)|(\\d{7,8})-(\\d{4}|\\d{3}|\\d{2}|\\d))$)";
    private static final DateTimeFormatter YMD_10 = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    private static final Pattern DATE_PATTERN = Pattern.compile(DATE_REGEX);


    private static final ZoneId ZONE_LOCAL = ZoneId.of("Asia/Shanghai");

    private static final ZoneOffset ZONE_OFFSET = ZoneOffset.of("+08:00");

    public static String FmtyyyyMMddStr(Long time) {
        SimpleDateFormat simpleDayHourFormat = new SimpleDateFormat("yyyyMMdd");
        return (null == time) ? null : simpleDayHourFormat.format(time);
    }

    public static String formatOf(Long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZONE_LOCAL);
        return YMD_14.format(dateTime);
    }


    /**
     * 正则匹配字符串是否为时间格式
     */
    public static boolean isNotDate(String date) {
        Matcher mat = DATE_PATTERN.matcher(date);
        return !mat.matches();
    }

    /**
     * 获取时间戳
     */
    public static Long timestampOfYmd14(String date) {
        LocalDateTime localDateTime = ofYmd14(date);
        if (null == localDateTime) {
            return null;
        }

        return localDateTime.atZone(ZONE_LOCAL).toInstant().toEpochMilli();
    }

    /**
     * 日期时间格式化
     *
     * @param date 时间日期
     * @return {@link LocalDate}
     */
    public static LocalDateTime ofYmd14(String date) {
        if (StrUtil.isBlank(date)) {
            return null;
        }

        try {
            return LocalDateTime.parse(date, YMD_14);
        } catch (RuntimeException ex) {
            log.warn("time parse err ", ex);
            return null;
        }
    }

    /**
     * 获取当前时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String NowTime() {
        return YMD_14.format(LocalDateTime.now());
    }

    public static String NowDate() {
        return YMD_10.format(LocalDateTime.now());
    }

    /**
     * yyyy-MM-dd 格式字符串转 LocalDate
     *
     * @param date yyyy-MM-dd
     * @return {@link LocalDate}
     */
    public static LocalDate formatYmd10(String date) {
        try {
            return LocalDate.parse(date, YMD_10);
        } catch (Exception ex) {
            log.warn("{} 无法解析为日期，解析过程发生错误", date, ex);
        }

        return null;
    }

    public static Long dayStart(Long timestamp) {
        if (null == timestamp) {
            return null;
        }

        Instant instant = Instant.ofEpochMilli(timestamp);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZONE_LOCAL);
        dateTime = LocalDateTime.of(dateTime.toLocalDate(), LocalTime.MIN);
        return dateTime.toInstant(ZONE_OFFSET).toEpochMilli();
    }

    public static Long dayEnd(Long timestamp) {
        if (null == timestamp) {
            return null;
        }

        Instant instant = Instant.ofEpochMilli(timestamp);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZONE_LOCAL);
        dateTime = LocalDateTime.of(dateTime.toLocalDate(), LocalTime.MAX);
        return dateTime.toInstant(ZONE_OFFSET).toEpochMilli();
    }

    /**
     * 获取 yyyy-MM-dd 格式年份数据
     *
     * @param yearsToSubtract 为 0 时获取当前时间，为 1 时获取去年时间，依此类推
     * @return yyyy-MM-dd
     */
    public static Integer year(int yearsToSubtract) {
        return LocalDate.now().minusYears(yearsToSubtract).getYear();
    }

    /**
     * 计算两个日期之间相差天数
     */
    public static Integer BetweenDays(LocalDate startDate, LocalDate endDate) {
    	if(null==startDate || null==endDate) {
    		return 0;
    	}
        return (int) (endDate.toEpochDay()-startDate.toEpochDay());
    }
    
}
